package com.manage.common.permissions.aspect;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.manage.common.core.constants.Constant;
import com.manage.common.core.enums.PermissionEnum;
import com.manage.common.core.utils.StringUtils;
import com.manage.common.permissions.annotation.HasPermissions;
import com.manage.system.api.feign.RemoteSystemMenu;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.List;
import java.util.Objects;

/**
 * 权限验证核心类
 *
 * @author zq
 */
@Aspect
@Component
@Slf4j
@AllArgsConstructor
public class PerAuthAspect {

    private final RemoteSystemMenu systemMenu;

    @Around("@annotation(com.manage.common.permissions.annotation.HasPermissions)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        HasPermissions annotation = method.getAnnotation(HasPermissions.class);
        if (annotation == null) {
            return point.proceed();
        }
        String authority = annotation.value();
        if (has(authority)) {
            return point.proceed();
        } else {
            PermissionEnum.FORBIDDEN.assertFail();
            return null;
        }
    }

    private boolean has(String authority) {
        // 用超管帐号方便测试，拥有所有权限
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String header = null;
        try {
            header = URLDecoder.decode(request.getHeader(Constant.CURRENT_USER), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        try {
            if (!StringUtils.isEmpty(header)) {
                JSONObject jsonObject = JSONUtil.parseObj(header);
                List authorities = jsonObject.get("authorities", List.class);
                if (authorities.contains(Constant.ADMIN)) {
                    return true;
                }
                Long userId = jsonObject.getLong("user_id");
                return systemMenu.selectPermsByUserId(userId).stream().anyMatch(authority::equals);
            } else {
                return false;
            }

        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }
}
